/* eslint-disable no-unused-vars */
/*
  扩展应用的后台脚本
  集中业务逻辑
  最后修改：2023-2-6
*/
const dayjs = require('dayjs')
var CTM = {}
import {
  _showPop,
  _getLocalStorage,
  _setLocalStorage,
  _objToFlat,
  _getLocalBookmark,
  _removeTree,
  _createBookmark,
  _createTabByurl,
  _fetch,
  _getBaseUrl,
  _setBaseUrl,
  _isDiff,
} from './background-utils'

// active: true 取当前激活的标签页
async function _findTab() {
  try {
    const currentWin = await chrome.windows.getCurrent({ populate: true })
    console.log('currentWin:', currentWin)
    const currentWinId = currentWin.id
    console.log('currentWin:', currentWin, 'currentWinId:', currentWinId)
    const activeTabs = await chrome.tabs.query({ active: true })
    const currentTab = activeTabs.find((e) => e.windowId == currentWinId)
    console.log('activeTabs:', activeTabs, 'currentTab:', currentTab)
    return currentTab
  } catch (e) {
    console.log('_findTab error', e)
  }
}

function sendToTab(_, back) {
  chrome.tabs.sendMessage(_.id, _.params, (r) => {
    back(r)
  })
}

async function _getLocalBookmarkVer() {
  return await _getLocalStorage('bookMarkVer')
}

async function _setLocalBookmarkVer(ver) {
  return await _setLocalStorage('bookMarkVer', ver)
}
async function _getTask() {
  let res = await _getLocalStorage('waitpush')
  return JSON.stringify(res) == '{}' ? 'NO' : res.waitpush
}

async function _setTask(action) {
  return await _setLocalStorage('waitpush', action)
}

// 监听回调
function handleInstalled() {
  console.log('call onInstalled')
}

//
// async function bookmarkListener(id, item) {
//   // await chrome.storage.local.set({ waitpush: 'YES' })
//   _showPop('', '1111111111111111')
// }

// // 启动收藏夹变更监听
// function startListeners() {
//   chrome.bookmarks.onCreated.addListener(bookmarkListener)
//   chrome.bookmarks.onChanged.addListener(bookmarkListener)
//   chrome.bookmarks.onChildrenReordered.addListener(bookmarkListener)
//   chrome.bookmarks.onImportBegan.addListener(bookmarkListener)
//   chrome.bookmarks.onImportEnded.addListener(bookmarkListener)
//   chrome.bookmarks.onMoved.addListener(bookmarkListener)
//   chrome.bookmarks.onRemoved.addListener(bookmarkListener)
// }

// // 停止收藏夹变更监听
// function stopListeners() {
//   chrome.bookmarks.onCreated.removeListener(bookmarkListener)
//   chrome.bookmarks.onChanged.removeListener(bookmarkListener)
//   chrome.bookmarks.onChildrenReordered.removeListener(bookmarkListener)
//   chrome.bookmarks.onImportBegan.removeListener(bookmarkListener)
//   chrome.bookmarks.onImportEnded.removeListener(bookmarkListener)
//   chrome.bookmarks.onMoved.removeListener(bookmarkListener)
//   chrome.bookmarks.onRemoved.removeListener(bookmarkListener)
// }

async function _bgRequest({ url, method = 'GET', body = {} }) {
  try {
    if (method == 'GET') {
      let resJson = await _fetch(url)
      return resJson.code == 0 ? resJson : { code: -1, data: 'result no match' }
    } else {
      console.log('method', method)
      let resJson = await _fetch({ url, method, body })
      return resJson.code == 0 ? resJson : { code: -1, data: 'result no match' }
    }
  } catch (e) {
    return { code: -1, data: e.message }
  }
}

// 获取云端备份
async function _PullBookMark() {
  try {
    let resJson = await _fetch('PullBookMark')
    return resJson.code == 0 ? resJson : { code: -1, data: 'result no match' }
  } catch (e) {
    return { code: -1, data: e.message }
  }
}

// 推送本地收藏夹到云端 并修改本地版本号
async function _PushBookMark() {
  try {
    let localBookmark = await _getLocalBookmark()
    // console.log('localBookmark:', localBookmark)
    let resJson = await _fetch({ url: 'PushBookMark', method: 'POST', body: { bookmark: JSON.stringify(localBookmark) } })
    if (resJson.code == 0) await _setLocalBookmarkVer(resJson.data.ver)
    return resJson
  } catch (e) {
    return { code: -1, data: e.message }
  }
}

// 清空本地收藏夹
async function _removeAll(nodelis) {
  let root = nodelis[0].children[0].children
  for (let node of root) await _removeTree(node.id)
  let rootOther = nodelis[0].children[1].children
  for (let node of rootOther) await _removeTree(node.id)
}

// 还原节点
async function _createBookmarkAll(root, pid = '') {
  // console.log('_createBookmarkAll #start:', root, pid)
  for (let node of root) {
    const _node = {}
    if (Object.hasOwnProperty.call(node, 'children')) {
      _node['parentId'] = pid
      _node['title'] = node.title
      // console.log('_createBookmark #1:', JSON.stringify(_node))
      let newNode = await _createBookmark(_node)
      // console.log('_createBookmarkAll #1:', node.children, newNode.id)
      await _createBookmarkAll(node.children, newNode.id)
    } else {
      _node['parentId'] = pid
      _node['title'] = node.title
      _node['url'] = node.url
      // console.log('_createBookmark #2:', JSON.stringify(_node))
      await _createBookmark(_node)
    }
  }
}

// 获取本地版本
async function getLocalBookmarkVer() {
  let res = await _getLocalBookmarkVer()
  return JSON.stringify(res) != '{}' ? res.bookMarkVer : ''
}

// 重置收藏夹
async function restoreBookmarkFromRemote(remoteBookmark, remoteVer) {
  // 清空本地收藏夹
  let localBookmark = await _getLocalBookmark()
  await _removeAll(localBookmark)

  // 重建主节点
  await _createBookmarkAll(remoteBookmark[0].children[0].children, '1')

  // 重建其他书签节点
  const otherRootPid = localBookmark[0].children[1].id
  await _createBookmarkAll(remoteBookmark[0].children[1].children, otherRootPid)

  // 更新本机版本号
  await _setLocalBookmarkVer(remoteVer)
  return true
}

// 合并收藏夹
async function mergeBookmarkWithBackup(bakBookmark) {
  // 原收藏夹
  let org = _objToFlat(bakBookmark)
  let localBookmark = await _getLocalBookmark()

  // 云端还原的收藏夹
  let current = _objToFlat(localBookmark)

  // 获取原收藏夹中云端未包含的url
  let noInclude = []
  let currentUrls = Object.keys(current)
  for (let url in org) {
    if (currentUrls.indexOf(url) > -1) continue
    noInclude.push(url)
  }

  if (noInclude.length == 0) return true

  // 新增合并节点
  let newNode = await _createBookmark({
    parentId: '1',
    title: dayjs().format('YYYYMMDD') + '合并',
  })

  const parentId = newNode.id
  for (let url of noInclude) {
    await _createBookmark({
      parentId,
      title: org[url].title,
      url: org[url].url,
    })
  }
}

// 仅同步到云端版本，即忽略本地当前收藏夹
async function restoreOnly() {
  // 获取云端备份内容
  let res = await _PullBookMark()
  const { code, data } = res
  if (code == -1) return _showPop('异常', data)

  // 云端暂无备份，推送本地收藏夹
  if (data.ver == '') return await _PushBookMark()

  let remoteVer = data.ver
  let remoteBookMark = JSON.parse(data.bookmark)

  return await restoreBookmarkFromRemote(remoteBookMark, remoteVer)
}

// 仅同步到云端版本，并将本地收藏夹于其合并到新版本
async function restoreAndMerge() {
  // 获取云端备份内容
  let res = await _PullBookMark()
  const { code, data } = res
  if (code == -1) return _showPop('异常', data)

  // 云端暂无备份，推送本地收藏夹
  if (data.ver == '') return await _PushBookMark()

  let remoteVer = data.ver
  let remoteBookMark = JSON.parse(data.bookmark)

  // 备份本机收藏夹,云端备份还原后，合并
  let localBookmarkBackup = await _getLocalBookmark()
  await restoreBookmarkFromRemote(remoteBookMark, remoteVer)

  // 合并本机收藏夹
  await mergeBookmarkWithBackup(localBookmarkBackup)
  // 推送合并后的收藏夹到云端
  return await _PushBookMark()
}

// 同步云端收藏夹
async function syncBookmark() {
  // 获取本地收藏夹版本，无版本号则提示手动选择同步完成初始化
  let localVer = await getLocalBookmarkVer()
  if (localVer == '') return _showPop('注意', '首次使用，请进行手动同步！')

  // 获取云端备份内容
  let res = await _PullBookMark()
  const { code, data } = res
  if (code == -1) return _showPop('异常', data)

  // 云端暂无备份，推送本地收藏夹
  if (data.ver == '') return await _PushBookMark()

  let remoteVer = data.ver
  let remoteBookMark = JSON.parse(data.bookmark)

  console.log('remoteVer:', remoteVer, 'localVer:', localVer)

  // 备份本机收藏夹,云端备份还原后，合并
  let localBookmark = await _getLocalBookmark()

  if (localVer < remoteVer) {
    // 云端版本号更高，云端覆盖本机,即同步到云端版本
    return await restoreBookmarkFromRemote(remoteBookMark, remoteVer)
  } else {
    // 版本号相同，且收藏夹内容有差异，以本地收藏夹为最新版本，推送到云端
    if (!_isDiff(remoteBookMark, localBookmark)) {
      console.log("content it's the diff,local content is to be push ")
      return await _PushBookMark()
    }
    console.log("content It's the same")
  }
}

// _setLocalStorage('ContextMenus', [
//   { id: 'M01', title: '通用带2021', action: 'updatePassword', type: 'autoWith2021', user: '', pwd: '' },
//   { id: 'M02', title: '通用', action: 'updatePassword', type: 'auto', user: '', pwd: '' },
//   { id: 'M03', title: 'gxjky', action: 'updatePassword', type: 'manual', user: '系统管理员', pwd: 'pkpmgxjky2021' },
// ])

async function createContextMenus() {
  let res = await _getLocalStorage('ContextMenus')
  if (JSON.stringify(res) == '{}') {
    const _default = [
      { id: 'M01', title: '通用带2021', action: 'updatePassword', type: 'autoWith2021', user: '', pwd: '' },
      { id: 'M02', title: '通用', action: 'updatePassword', type: 'auto', user: '', pwd: '' },
      { id: 'M03', title: 'gxjky', action: 'updatePassword', type: 'manual', user: '系统管理员', pwd: 'pkpmgxjky2021' },
    ]
    _setLocalStorage('ContextMenus', _default)
    res = { ContextMenus: _default }
  }

  for (let item of res.ContextMenus) {
    const { id, title } = item
    CTM[id] = item
    chrome.contextMenus.create({ id, title, contexts: ['all'] })
  }
}

function resetContextMenus() {
  chrome.contextMenus.removeAll(() => {
    createContextMenus()
    return true
  })
}

// *************************************************************//
// 主程序开始
console.log('background.js restart on :', dayjs().format('YYYY-MM-DD hh-mm'))

/*************************************************************
 监听 permissions 配置的插件注册完成
 在 onInstalled 监听器内部，扩展使用 storage API 设置一个值。这将允许多个扩展组件访问该值并进行更新。
 大部分 API，包括 storage api，必须被注册在 manifest 的 permissions 字段中给插件使用。
************************************************************/
chrome.runtime.onInstalled.addListener(handleInstalled)

/*
右键菜单 命令转发中心
*/
resetContextMenus()
// 右键菜单点击事件监听。
chrome.contextMenus.onClicked.addListener((info, tab) => {
  const { action, type, user, pwd } = CTM[info.menuItemId]
  chrome.tabs.sendMessage(tab.id, { action, params: { type, user, pwd } }, {}, () => {
    return true
  })
  return true
})

/*************************************************************
 service worker Api
 响应各扩展应用的请求 
 data示例
 {
    action:"getLocalBookmark",
    params:"",
 }
 ************************************************************/
const SWAPI = {
  bgRequest: async (_, back) => {
    console.log('### _', _)
    const r = await _bgRequest(_)
    back(r)
  },
  saveContextMenus: async (_, back) => {
    const r = await _setLocalStorage('ContextMenus', _.ContextMenus)
    resetContextMenus()
    back(r)
  },

  saveIdAutoEnterRule: async (_, back) => {
    // console.log('saveIdAutoEnterRule', _)
    const r = await _setLocalStorage('IdAutoEnterRule', _.IdAutoEnterRule)
    resetContextMenus()
    back(r)
  },

  getContextMenus: async (_, back) => {
    back(await _getLocalStorage('ContextMenus'))
  },

  getIdAutoEnterRule: async (_, back) => {
    back(await _getLocalStorage('IdAutoEnterRule'))
  },

  getwaitpush: async (_, back) => {
    back(await _getTask())
  },
  setwaitpush: async (_, back) => {
    back(await _setTask(_.waitpush))
  },
  getBaseUrl: async (_, back) => {
    back(await _getBaseUrl())
  },
  setBaseUrl: async (_, back) => {
    back(await _setBaseUrl(_.baseUrl))
  },
  sendToTab,
  showPop: (_, back) => {
    _showPop(_.title, _.msg)
    back({})
  },
  navTo: (_, back) => {
    _createTabByurl(_.url)
    back({})
  },
  findTabs: async (_, back) => {
    back(await _findTab(_))
  },
  getLocalBookmark: async (_, back) => {
    back(await _getLocalBookmark())
  },
  getLocalBookmarkVer: async (_, back) => {
    back(await _getLocalBookmarkVer())
  },
  setLocalBookmarkVer: async (_, back) => {
    back(await _setLocalBookmarkVer(_.ver))
  },
  pullBookMark: async (_, back) => {
    back(await _PullBookMark())
  },
  pushBookMark: async (_, back) => {
    back(await _PushBookMark())
  },
  restoreOnly: async (_, back) => {
    back(await restoreOnly())
  },
  restoreAndMerge: async (_, back) => {
    back(await restoreAndMerge())
  },
}

function serviceWorkerListener(data, sender, back) {
  // console.log('SWAPI => Action received :', data, sender)
  if (Object.hasOwnProperty.call(data, 'action')) {
    SWAPI[data.action](data.params, back)
    return true
  }
}

chrome.alarms.onAlarm.addListener(async (alarm) => {})
chrome.runtime.onMessage.addListener(serviceWorkerListener)
chrome.alarms.create('main', { periodInMinutes: 1 })
syncBookmark()
